#pragma once
#include "DAEFloat4.h"
#include "DAEFloat3.h"
#include "DAEMatrix33.h"

#include "memory.h"
/**
* Value class for 4x4 matrices.
* The Transform class uses an internal matrix to store the 
* matrix that is determined by the different parameters.
* The native format for this matrix is row major order, which
* is the same format as DirectX.
* @author Koen Samyn
*/
class DAEMatrix: public FXValue
{
public:
	/**
	* Creates a new DAEMatrix object.
	*/
	DAEMatrix(void);
	/**
	* Destroys the DAEMatrix object
	*/
	~DAEMatrix(){
	}

	/**
	* Copy the values from another matrix.
	* @param matrix the other matrix
	*/
	void SetValues(const DAEMatrix& matrix)
	{
		memcpy(m_RMData, matrix.m_RMData,16*sizeof(float));
	}

	/**
	* Sets the value for a cell in the matrix.
	* @param row a number between 0 and 3 that indicates the row of
	* the cell.
	* @param column a number between 0 and 3 that indicates the column of
	* the cell.
	* @param value the value to set in the cell.
	*/
	void SetCell(int row, int column, float value);
	/**
	* Returns the value for a cell in the matrix.
	 @param row a number between 0 and 3 that indicates the row of
	* the cell.
	* @param column a number between 0 and 3 that indicates the column of
	* the cell.
	* @return the value of the cell
	*/
	float GetCell(int row, int column) const;
	/**
	* Fills an entire row with a given DAEFloat4 value.
	* @param row a number between 0 and 3 that indicates the row to fill.
	* @param value A DAEFloat4 object to fill the row with.
	*/ 
	void SetRow(int row, DAEFloat4& value);
	/**
	* Fills an entire row with the 4 float parameters.
	* @param row a number (0 to 3) that indicates the row to fill.
	* @param a1 the first value in the row.
	* @param a2 the second value in the row.
	* @param a3 the third value in the row.
	* @param a4 the fourth value in the row.
	*/
	void SetRow(int row, float a1, float a2, float a3, float a4);
	/**
	* Fills an entire column with a given DAEFloat4 value.
	* @param column a number (0 to 3) that indicates the row to fill.
	* @param value a DAEFloat4 object to fill the column with.
	*/
	void SetColumn(int column, DAEFloat4& value);
	/**
	* Fills an entire column with the 4 float parameters.
	* @param column a number (0 to 3) that indicates the row to fill.
	* @param a1 the first value in the column.
	* @param a2 the second value in the column.
	* @param a3 the third value in the column.
	* @param a4 the fourth value in the column.
	*/
	void SetColumn(int column, float a1, float a2, float a3, float a4);
	/**
	* Fills the data of one row into the provided DAEFloat4 object.
	* @param row the row to get.
	* @param value the DAEFloat4 object to fill.
	*/
	void GetRow(int row, DAEFloat4& value) const;
	/**
	* Fills the data of one column into the provided DAEFloat4 object.
	* @param column the column to get.
	* @param value the DAEFloat4 object to fill.
	*/
	void GetColumn(int row, DAEFloat4& value) const;

	/**
	* Replaces the values in this matrix with the identity matrix.
	*/
	void SetAsIdentity();
	/**
	* Transforms a vector with this matrix and stores the result
	* in vOut.
	* @param vOut the DAEFloat3 object to store the result in.
	* @param vToTransform the DAEFloat3 object to transform.
	*/
	void TransformVector(DAEFloat3& vOut, DAEFloat3& vToTransform) const;
	/**
	* Transforms a vector with this matrix and stores the result
	* in vOut.
	* @param vOut the DAEFloat4 object to store the result in.
	* @param vToTransform the DAEFloat3 object to transform.
	*/
	void TransformVector(DAEFloat4& vOut, DAEFloat3& vToTransform)const;
	/**
	* Transforms a vector with this matrix and stores the result
	* in vOut. The translation part of the matrix will not be applied.
	* @param vOut the DAEFloat3 object to store the result in.
	* @param vToTransform the DAEFloat3 object to transform.
	*/
	void TransformNormal(DAEFloat3& vOut, DAEFloat3& vToTransform) const;
	/**
	* Multiplies this matrix with another matrix , and
	* stores the result in the mOut variable.
	* @param mOut a pointer to a DAEMatrix object that will store the result.
	* @param toMultiply the DAEMatrix to multiply this matrix with.
	*/
	void Multiply(DAEMatrix* mOut, const DAEMatrix* toMultiply);
	/**
	* Returns the size of the value in bytes.
	* @return the size in bytes.
	*/
	int GetSizeInBytes() const{
		return 16*sizeof(float);
	}
	/**
	* Returns the pointer to the beginning of the value.
	* @return a void pointer to the beginning of the value.
	*/
	const void* GetValuePointer() const{
		return m_RMData;
	}

	/**
	* Calculates the determinant of this matrix.
	* @return the determinant of the matrix.
	*/
	float Determinant() const;
	/**
	* Calculates the inverse matrix.
	* @param mOut the out variable that will start the resulting matrix.
	*/
	void Inverse(DAEMatrix& inverse) const;

	/**
	* Stores the result of deleting the provided
	* row and and column from this matrix into the
	* mOut 3x3 matrix.
	*/
	void GetMinor(DAEMatrix33& mOut, int row, int column)const;

	/**
	* Copies the data from the toCopy matrix to this matrix.
	* @param toCopy the array to copy.
	*/
	/*
	DAEMatrix(const DAEMatrix& toCopy){
		memcpy(m_RMData, toCopy.m_RMData,16*sizeof(float));
	}*/

	/**
	* Assigns an other DAEMatrix to this DAEMatrix. 
	*/
	/*
	DAEMatrix& DAEMatrix::operator=( const DAEMatrix& toCopy ) {
		memcpy(m_RMData, toCopy.m_RMData,16*sizeof(float));
		return *this;
	}*/

private:
	/**
	* The 16 floats that determine the matrix
	* in row major order (DirectX compatible)
	*/
	float m_RMData[16];
};
